var EXPORTED_SYMBOLS = ["run_tests"];

const ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);

var num_tests_finished = 0;

function test_sftp_upload() {
    var stringStream = Components.classes["@mozilla.org/io/string-input-stream;1"].createInstance(Components.interfaces.nsIStringInputStream);
    var data = "This is the contents of file.txt\n";
    stringStream.setData(data, -1);

    var spec = "sftp://test:testuser@localhost/home/test/file.txt";
    var uri = ioService.newURI(spec, null, null);
    var channel = ioService.newChannelFromURI(uri);
    var contentType = "text/xml";
    try {
        channel = channel.QueryInterface(Components.interfaces.nsIUploadChannel);
    } catch(ex) {
        throw("Channel does not support uloading");
    }
    // Set the upload stream, this is the deciding factor of whether the channel
    // performs and upload or a download when asyncOpen() is called.
    channel.setUploadStream(stringStream, contentType, -1);

    var dataAvailableCallback = {
        onStartRequest: function(channel, ctxt) {
            //dump("onStartRequest\n");
        },
        onDataAvailable: function(channel, ctxt, input, sourceOffset, count) {
            //dump("onDataAvailable\n");
        },
        onStopRequest: function(channel, ctxt, status) {
            if (status == Components.results.NS_OK) {
                dump("test_sftp_upload:             OK\n");
            } else {
                dump("test_sftp_upload:             *** FAIL *** (" + ex + ")\n");
            }
            num_tests_finished += 1;
        }
    };

    channel.asyncOpen(dataAvailableCallback, null);
}

function test_sftp_download() {
    var spec = "sftp://test:testuser@localhost/home/test/file.txt";
    var uri = ioService.newURI(spec, null, null);
    var channel = ioService.newChannelFromURI(uri);

    var received_data = [];
    var dataAvailableCallback = {
        onDataAvailable: function(channel, ctxt, input, sourceOffset, count) {
            const sis = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
            sis.init(input);
            var read_data = sis.read(count);
            received_data.push(read_data);
            //dump("onDataAvailable: '" + read_data + "'\n");
        },
        onStartRequest: function(channel, ctxt) {
            //dump("onStartRequest\n");
        },
        onStopRequest: function(channel, ctxt, status) {
            //dump("onStopRequest\n");
            if (status == Components.results.NS_OK) {
                var data = received_data.join("");
                if (data == "This is the contents of file.txt\n") {
                    dump("test_sftp_download:           OK\n");
                } else {
                    dump("test_sftp_download:           *** FAIL *** (data: '" + data + "')\n");
                }
            } else {
                dump("test_sftp_download:           *** FAIL *** (" + ex + ")\n");
            }
            num_tests_finished += 1;
        }
    };

    channel.asyncOpen(dataAvailableCallback, null);
};

function test_sftp_binary_upload() {
    var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
    file.initWithPath("/bin/gzip");
    var fis = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
    fis.init(file, -1, 0, 0);

    var is = Components.classes["@mozilla.org/network/buffered-input-stream;1"].createInstance(Components.interfaces.nsIBufferedInputStream);
    is.init(fis, 8192);

    var spec = "sftp://test:testuser@localhost/home/test/tmp/gzip";
    var uri = ioService.newURI(spec, null, null);
    var channel = ioService.newChannelFromURI(uri);
    try {
        channel = channel.QueryInterface(Components.interfaces.nsIUploadChannel);
    } catch(ex) {
        throw("Channel does not support uloading");
    }

    // Set the upload stream, this is the deciding factor of whether the channel
    // performs and upload or a download when asyncOpen() is called.
    var contentType = "";
    channel.setUploadStream(is, contentType, -1);

    var dataAvailableCallback = {
        onStartRequest: function(channel, ctxt) {
            //dump("onStartRequest\n");
        },
        onDataAvailable: function(channel, ctxt, input, sourceOffset, count) {
            //dump("onDataAvailable\n");
        },
        onStopRequest: function(channel, ctxt, status) {
            //dump("onStopRequest\n");
            if (status == Components.results.NS_OK) {
                dump("test_sftp_binary_upload:      OK\n");
            } else {
                dump("test_sftp_binary_upload:      *** FAIL *** (" + ex + ")\n");
            }
            num_tests_finished += 1;
        }
    };

    channel.asyncOpen(dataAvailableCallback, null);
}

function test_ssh_run_command() {
    var spec = "ssh://test:testuser@localhost/";
    var uri = ioService.newURI(spec, null, null);
    var channel = ioService.newChannelFromURI(uri);
    try {
        channel = channel.QueryInterface(Components.interfaces.pyISSHCommand);
    } catch(ex) {
        throw("Channel does not support ssh commands");
    }
    var received_data = [];
    var dataAvailableCallback = {
        onStartRequest: function(channel, ctxt) {
            //dump("onStartRequest\n");
        },
        onDataAvailable: function(channel, ctxt, input, sourceOffset, count) {
            //dump("onDataAvailable\n");
            const sis = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
            sis.init(input);
            var read_data = sis.read(count);
            received_data.push(read_data);
        },
        onStopRequest: function(channel, ctxt, status) {
            if (status == Components.results.NS_OK) {
                var data = received_data.join("");
                if (data == "hello there\n") {
                    dump("test_sftp_download:           OK\n");
                } else {
                    dump("test_sftp_download:           *** FAIL *** (data: '" + data + "')\n");
                }
            } else {
                dump("test_ssh_run_command:         *** FAIL *** (" + ex + ")\n");
            }
            num_tests_finished += 1;
        }
    };

    var command = "echo 'hello there'";
    channel.asyncRunCommand(dataAvailableCallback, command, null);
}

/**
 * Run the tests.
 */

function run_tests() {
    try {
        test_sftp_upload();
    } catch(ex) {
        num_tests_finished += 1;
        dump("test_sftp_upload:             *** FAIL *** (" + ex + ")\n");
    }

    try {
        test_sftp_download();
    } catch(ex) {
        num_tests_finished += 1;
        dump("test_sftp_download:           *** FAIL *** (" + ex + ")\n");
    }

    try {
        test_sftp_binary_upload();
    } catch(ex) {
        num_tests_finished += 1;
        dump("test_sftp_binary_upload:      *** FAIL *** (" + ex + ")\n");
    }

    try {
        test_ssh_run_command();
    } catch(ex) {
        test_ssh_run_command += 1;
        dump("test_ssh_run_command:         *** FAIL *** (" + ex + ")\n");
    }

    // This code needs to be used when running standalone with xpcshell.
    //dump("*** running event loop\n");
    //var thr = Components.classes["@mozilla.org/thread-manager;1"].getService().currentThread;
    //while (num_tests_finished < 4) {
    //    thr.processNextEvent(true);
    //}
    //while (thr.hasPendingEvents()) {
    //    thr.processNextEvent(true);
    //}

}

run_tests();
